package com.ruoyi.syrw.common;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.math3.fitting.GaussianCurveFitter;
import org.apache.commons.math3.fitting.PolynomialCurveFitter;
import org.apache.commons.math3.fitting.SimpleCurveFitter;
import org.apache.commons.math3.fitting.WeightedObservedPoints;
import org.apache.commons.math3.stat.regression.RegressionResults;
import org.apache.commons.math3.stat.regression.SimpleRegression;


@Slf4j
public class LineUtil {


    /**
     * 得到一元一次函数 y=kx+b 的k，b
     *
     * @param data eg； {{1d, 1.1d}, {2d, 2.1d}, {3d, 3.1d}, ....}
     * @return LineFunction 里面有直线的参数 k ，b
     */
    public static LineFunction getGeneralLine(double[][] data) {
        if (data.length == 2) {
            // 数量不足以回归
            double k = (data[0][1] - data[1][1]) / (data[0][0] - data[1][0]);
            double b = data[0][1] - (k * data[0][0]);
            return new LineFunction(k, b);
        }
        SimpleRegression regression = new SimpleRegression();
        regression.addData(data);
        RegressionResults results = regression.regress();
        return new LineFunction(results.getParameterEstimate(1), results.getParameterEstimate(0));
    }


    /**
     * 得到一元二次函数 y=ax²+bx+c 的a,b,c
     *
     * @param data 用来拟合的数据点 eg； {{1d, 1.1d}, {2d, 2.1d}, {3d, 3.1d}, ....}
     *             //     * @param guess 函数猜测值
     * @return LineFunction 里面有直线的参数 k ，b
     */
    public static QuadFunction getQuadFuncLine(double[][] data) {
        PolynomialCurveFitter fitter = PolynomialCurveFitter.create(2);


//        ParametricUnivariateFunction function = new PolynomialFunction.Parametric();
//        SimpleCurveFitter curveFitter = SimpleCurveFitter.create(function, guess);
        WeightedObservedPoints observedPoints = new WeightedObservedPoints();
        for (double[] datum : data) {
            observedPoints.add(datum[0], datum[1]);
        }

//        double[] best = curveFitter.fit(observedPoints.toList());
        double[] best = fitter.fit(observedPoints.toList());
        return new QuadFunction(best[2], best[1], best[0]);
    }


    /**
     * 得到级配曲线函数 p =  100 / ((1 - b) * Math.pow((60 / d), m)) + b;
     *
     * @param data (d,p)  eg； {{1d, 1.1d}, {2d, 2.1d}, {3d, 3.1d}, ....}
     * @return LineFunction 里面有直线的参数 k ，b
     */
    public static JiPeiFunction getJiPeiFuncLine(double[][] data) {
        JiPeiFunction function = new JiPeiFunction();
        double[] guess = {0.97329, 1.33716};
        SimpleCurveFitter curveFitter = SimpleCurveFitter.create(function, guess);
        WeightedObservedPoints observedPoints = new WeightedObservedPoints();
        for (double[] point : data) {
            observedPoints.add(point[0], point[1]);
        }
        double[] best = curveFitter.fit(observedPoints.toList());
        log.debug("best: {}, {}", best[0], best[1]);
        return new JiPeiFunction(best);
    }

    /**
     * 得到指数函数 y = a * e^bx ;
     *
     * @param data (d,p)  eg； {{1d, 1.1d}, {2d, 2.1d}, {3d, 3.1d}, ....}  [[142,0.3],[270,0.6],[473,1],[805,2],[902,2.5]]
     * @return GaussianFunction 里面有指数函数的参数 a ，b
     */
    @Deprecated
    public static GaussianFunction getGaussianFuncLine(double[][] data) {
//        PolynomialCurveFitter fitter = PolynomialCurveFitter.create(1);
        GaussianCurveFitter fitter = GaussianCurveFitter.create();
        WeightedObservedPoints observedPoints = new WeightedObservedPoints();
        for (double[] point : data) {
            observedPoints.add(point[0], point[1]);
        }
        double[] best = fitter.fit(observedPoints.toList());
        log.debug("best: {}, {}", best[0], best[1]);
        return new GaussianFunction(best[0], best[1]);
    }


}
